// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: jing

#include "coin2/exchange/factory/feed/raw_processor.h"

#include <memory>

#include "coin2/exchange/base/feed/ws/request_generator.h"
#include "coin2/exchange/binance/feed_v1/request_generator.h"
#include "coin2/exchange/binanceus/feed_v1/request_generator.h"
#include "coin2/exchange/binance_futures/feed_v1/request_generator.h"
#include "coin2/exchange/bithumb/feed_v2/request_generator.h"
#include "coin2/exchange/bybit/feed_v1/request_generator.h"
#include "coin2/exchange/bybit/feed_v3/request_generator.h"
#include "coin2/exchange/coinone/feed_v2/request_generator.h"
#include "coin2/exchange/gopax/feed_v1/request_generator.h"
#include "coin2/exchange/huobi/feed_v1/request_generator.h"
#include "coin2/exchange/huobi_futures/feed_v1/request_generator.h"
#include "coin2/exchange/upbit/feed_v1/request_generator.h"
#include "coin2/exchange/quoinex/feed_v2/request_generator.h"
#include "coin2/exchange/okex_futures/feed_v3/request_generator.h"
#include "coin2/exchange/okex_common/feed_v5/request_generator.h"
#include "coin2/exchange/ftx_common/feed_v1/request_generator.h"
#include "coin2/exchange/deribit_base/feed_v2/request_generator.h"
#include "coin2/exchange/prex_base/feed_v1/request_generator.h"
#include "coin2/exchange/gateio/feed_v4/request_generator.h"
#include "coin2/exchange/phemex_base/feed_v1/request_generator.h"
#include "coin2/exchange/kucoin_futures/feed_v1/request_generator.h"
#include "coin2/exchange/bybit_futures/feed_v2/request_generator.h"
#include "coin2/exchange/bybit_futures/feed_v3/request_generator.h"
#include "coin2/exchange/bitmex/feed_v1/request_generator.h"
#include "coin2/exchange/dydx_futures/feed_v3/request_generator.h"
#include "coin2/exchange/bitbank/feed_v1/request_generator.h"
#include "coin2/exchange/gdax/feed_v1/request_generator.h"
#include "coin2/exchange/kraken/feed_v1/request_generator.h"
#include "coin2/exchange/btcturk/feed_v1/request_generator.h"
#include "coin2/exchange/crypto_common/feed_v2/request_generator.h"
#include "coin2/exchange/mexc/feed_v2/request_generator.h"
#include "coin2/exchange/mexc/feed_v3/request_generator.h"
#include "coin2/exchange/kucoin/feed_v1/request_generator.h"
#include "coin2/exchange/coingecko/feed_v3/request_generator.h"
#include "coin2/exchange/bitget/feed_v1/request_generator.h"
#include "coin2/exchange/bitget_futures/feed_v1/request_generator.h"
#include "coin2/exchange/mercado/feed_v4/request_generator.h"
#include "coin2/exchange/korbit/feed_v1/request_generator.h"
#include "coin2/exchange/bitmart/feed_v3/request_generator.h"
#include "coin2/exchange/lbank/feed_v2/request_generator.h"
#include "coin2/exchange/bit/feed_v1/request_generator.h"
#include "coin2/exchange/maicoin/feed_v2/request_generator.h"
#include "coin2/exchange/bittrex/feed_v3/request_generator.h"

using namespace coin::proto;

namespace coin2::exchange::factory::feed::impl {

using RequestGenerator = coin2::exchange::base::feed::RequestGenerator;
using coin2::exchange::feed::WebsocketConfig;

std::unique_ptr<base::feed::RequestGenerator> NewRequestGenerator(
    const MarketExchangeApi& mea,
    const WebsocketConfig* ws_config) {

  if (mea == MarketExchangeApi{Spot, ExchangeType::Huobi, "v1"}) {
    return std::make_unique<huobi::feed_v1::HuobiRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, ExchangeType::Huobi, "v1-mbp5"}) {
    return std::make_unique<RequestGenerator>();
  } else if (mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1-swap"} ||
             mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1-swap-noti"} ||
             mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1-linear-swap"}) {
    return std::make_unique<huobi_futures::feed_v1::HuobiFuturesSwapRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1"} ||
             mea == MarketExchangeApi {Futures, ExchangeType::Huobi, "v1-noti"}) {
    return std::make_unique<huobi_futures::feed_v1::HuobiFuturesRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Bitmex, "v1"}) {
    return std::make_unique<bitmex::feed_v1::BitmexRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Okex, "v3"}) {
    return std::make_unique<RequestGenerator>();
  } else if (mea == MarketExchangeApi {Futures, Okex, "v3"}
             || mea == MarketExchangeApi{Futures, Okex, "v3-swap"}) {
    return std::make_unique<okex_futures::feed_v3::OkexFuturesRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Okex, "v5"}) {
    return std::make_unique<okex_common::feed_v5::OkexCommonRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi {Futures, Okex, "v5"}
             || mea == MarketExchangeApi{Futures, Okex, "v5-swap"}) {
    return std::make_unique<okex_common::feed_v5::OkexCommonRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Binance, "v1"}) {
    return std::make_unique<binance_futures::feed_v1::BinanceFuturesRequestGenerator>(ws_config);
  } else if ((mea == MarketExchangeApi{Spot, Binance, "v1"})) {
    return std::make_unique<binance::feed_v1::BinanceRequestGenerator>(ws_config);
  } else if ((mea == MarketExchangeApi{Spot, Binanceus, "v1"})) {
    return std::make_unique<binance_us::feed_v1::BinanceUsRequestGenerator>();
  } else if ((mea == MarketExchangeApi{Futures, Binance, "v1-delivery"})) {
    return std::make_unique<binance_futures::feed_v1::BinanceFuturesRequestGenerator>(ws_config);
  }
  else if (mea == MarketExchangeApi{Spot, Kraken, "v1"}) {
    return std::make_unique<kraken::feed_v1::KrakenRequestGenerator>(ws_config);
  } else if (
    (mea == MarketExchangeApi{Spot, Upbit, "v1"}) ||
    (mea == MarketExchangeApi{Spot, Upbitsg, "v1"}) ||
    (mea == MarketExchangeApi{Spot, Upbitid, "v1"}) ||
    (mea == MarketExchangeApi{Spot, Upbitth, "v1"})) {
    return std::make_unique<upbit::feed_v1::UpbitRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Coinone, "v2"}) {
    return std::make_unique<coinone::feed_v2::CoinoneRequestGenerator>();
  } else if (mea == MarketExchangeApi{Spot, Gdax, "v1"}) {
    return std::make_unique<gdax::feed_v1::GdaxRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Gopax, "v1"}) {
    return std::make_unique<gopax::feed_v1::GopaxRequestGenerator>();
  } else if (mea == MarketExchangeApi{Spot, Quoinex, "v2"}) {
    return std::make_unique<quoinex::feed_v2::QuoinexRequestGenerator>();
  } else if (mea == MarketExchangeApi{Spot, Bithumb, "v2"}) {
    return std::make_unique<bithumb::feed_v2::BithumbRequestGenerator>();
  } else if (mea == MarketExchangeApi{Futures, Bitflyer, "v1"}) {
    return std::make_unique<RequestGenerator>();
  } else if (mea == MarketExchangeApi{Spot, Bybit, "v1"}) {
    return std::make_unique<bybit::feed_v1::BybitRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Bybit, "v2"} ||
             mea == MarketExchangeApi{Futures, Bybit, "v2-linear"}) {
    return std::make_unique<bybit_futures::feed_v2::BybitFuturesRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Bybit, "v3"}) {
    return std::make_unique<bybit::feed_v3::BybitRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Bybit, "v3"} ||
             mea == MarketExchangeApi{Futures, Bybit, "v3-linear"} ||
             mea == MarketExchangeApi{Futures, Bybit, "v3-linear-usdc"}) {
    return std::make_unique<bybit_futures::feed_v3::BybitFuturesRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Ftx, "v1"}) {
    return std::make_unique<ftx_common::feed_v1::FtxCommonRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Ftx, "v1"}) {
    return std::make_unique<ftx_common::feed_v1::FtxCommonRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Bitstamp, "v2"}) {
    return std::make_unique<RequestGenerator>();
  } else if (mea == MarketExchangeApi{Spot, Prex, "v1"} ||
             mea == MarketExchangeApi{Futures, Prex, "v1"}) {
    return std::make_unique<prex_base::feed_v1::PrexBaseRequestGenerator>();
  } else if (mea == MarketExchangeApi{Spot, Korbit, "v1"}) {
    return std::make_unique<korbit::feed_v1::KorbitRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Bitbank, "v1"}) {
    return std::make_unique<bitbank::feed_v1::BitbankRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Deribit, "v2"} ||
             mea == MarketExchangeApi{Options, Deribit, "v2"} ||
             mea == MarketExchangeApi{Index, Deribit, "v2"}) {
    return std::make_unique<deribit_base::feed_v2::DeribitRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Coincheck, "v1"}) {
    return std::make_unique<RequestGenerator>();
  } else if (mea == MarketExchangeApi{Spot, Gateio, "v4"} ||
             mea == MarketExchangeApi{Futures, Gateio, "v4-btc"} ||
             mea == MarketExchangeApi{Futures, Gateio, "v4"} ||
             mea == MarketExchangeApi{Futures, Gateio, "v4-delivery-btc"} ||
             mea == MarketExchangeApi{Futures, Gateio, "v4-delivery"}) {
    return std::make_unique<gateio::feed_v4::GateioRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Phemex, "v1"} ||
             mea == MarketExchangeApi{Spot, Phemex, "v1"} ||
             mea == MarketExchangeApi{Futures, Phemex, "v1-linear"}) {
    return std::make_unique<phemex_base::feed_v1::PhemexRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Kucoin, "v1"}) {
    return std::make_unique<kucoin::feed_v1::KucoinSpotRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Kucoin, "v1"}) {
    return std::make_unique<kucoin_futures::feed_v1::KucoinFuturesRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Dydx, "v3"}) {
    return std::make_unique<dydx_futures::feed_v3::DydxFuturesRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Btcturk, "v1"}) {
    return std::make_unique<btcturk::feed_v1::BtcturkRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Crypto, "v2"} ||
             mea == MarketExchangeApi{Futures, Crypto, "v1"}) {
    return std::make_unique<crypto_common::feed_v2::CryptoRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Mexc, "v1"}) {
    return std::make_unique<RequestGenerator>();
  } else if (mea == MarketExchangeApi{Spot, Mexc, "v2"}) {
    return std::make_unique<mexc::feed_v2::MexcSpotRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Mexc, "v3"}) {
    return std::make_unique<mexc::feed_v3::MexcSpotRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Coingecko, "v3"}) {
    return std::make_unique<coingecko::feed_v3::CoingeckoRequestGenerator>();
  } else if (mea == MarketExchangeApi{Spot, Bitget, "v1"}) {
    return std::make_unique<bitget::feed_v1::BitgetRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Bitget, "v1"}) {
    return std::make_unique<bitget_futures::feed_v1::BitgetFuturesRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Spot, Lbank, "v2"}) {
    return std::make_unique<lbank::feed_v2::LbankSpotRequestGenerator>(ws_config);
  } else if (mea == MarketExchangeApi{Futures, Apollox, "v1"}) {
    return std::make_unique<binance_futures::feed_v1::BinanceFuturesRequestGenerator>(ws_config);
  } else if ((mea == MarketExchangeApi{Spot, Apollox, "v1"})) {
    return std::make_unique<binance::feed_v1::BinanceRequestGenerator>(ws_config);
  } else if ((mea == MarketExchangeApi{Spot, Mercado, "v4"})) {
    return std::make_unique<mercado::feed_v4::MercadoRequestGenerator>(ws_config);
  } else if ((mea == MarketExchangeApi{Spot, Bitmart, "v3"})) {
    return std::make_unique<bitmart::feed_v3::BitmartRequestGenerator>(ws_config);
  } else if ((mea == MarketExchangeApi{Spot, Bit, "v1"})) {
    return std::make_unique<bit::feed_v1::BitRequestGenerator>(ws_config);
  } else if ((mea == MarketExchangeApi{Spot, Uniswap, "v2"} ||
              mea == MarketExchangeApi{Spot, Uniswap, "v3"} ||
              mea == MarketExchangeApi{Spot, Uniswap, "v3-arbitrum"})) {
    return std::make_unique<RequestGenerator>();
  } else if ((mea == MarketExchangeApi{Spot, Maicoin, "v2"})) {
    return std::make_unique<maicoin::feed_v2::MaicoinRequestGenerator>(ws_config);
  } else if ((mea == MarketExchangeApi{Spot, Bittrex, "v3"})) {
    return std::make_unique<bittrex::feed_v3::BittrexRequestGenerator>(ws_config);
  } else {
    THROW() << "[RequestGenerator Factory] not implemented for " << mea.String();
  }
  return {};
}

}  // namespace coin2::exchange::factory::feed::impl
